#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

typedef struct Var_t              /*  Variables sent to threads   */
{
    char            buf[200];
    pthread_mutex_t mutex;
}Var;


void* PingThread(void* _var)
{
    assert(_var);

    while(1)
    {
        /*puts("Thread1: try locking mutex");*/
        if(pthread_mutex_lock((pthread_mutex_t*)(&((Var*)_var)->mutex)))    /*  locking mutex       */
        {
            fprintf(stderr, "error in locking mutex\n");
        }
        /*puts("Thread1: mutex locked");*/

        puts("ping");

        /*strcpy((((Var*)_var)->buf), "ping");*/                                /*  puts ping in buffer */



        /*puts("Thread1: unlocking mutex");*/
        pthread_mutex_unlock((pthread_mutex_t*)(&((Var*)_var)->mutex));     /*  unlock mutex        */
        /*sleep(1);*/
        sched_yield();
    }


    pthread_exit(0);

    return 0;
}


void* PongThread(void* _var)
{
    assert(_var);


    while(1)
    {
        /*puts("Thread2: try locking mutex");*/
        if(pthread_mutex_lock((pthread_mutex_t*)(&((Var*)_var)->mutex)))    /*  locking mutex           */
        {
            fprintf(stderr, "error in locking mutex\n");
        }

        /*puts("Thread2: mutex locked");*/

        puts("pong");


        /*puts("Thread2: unlocking mutex");*/
        pthread_mutex_unlock((pthread_mutex_t*)(&((Var*)_var)->mutex));     /*  unlock mutex            */
        /*sleep(1);*/
        sched_yield();
    }


    pthread_exit(0);

    return 0;
}

int main()
{
    pthread_t               tid[2]  ;                   /*  the ID's of threads */
    pthread_mutexattr_t     mutAtr  ;
    Var                     v       ;

    pthread_mutexattr_init(&mutAtr);                                   /*  init attributes of mutex                                */
    pthread_mutexattr_setpshared(&mutAtr, PTHREAD_PROCESS_PRIVATE);    /*  Set to threads shared                                   */
    pthread_mutexattr_settype(&mutAtr, PTHREAD_MUTEX_RECURSIVE);       /*  Only process that locked can unlock. Mutex Re-entrant   */
    if(pthread_mutex_init(&v.mutex, &mutAtr))                          /*  Init the mutex with the above attributes                */
    {
        fprintf(stderr, "error in initializing mutex\n");
        return 1;
    }


    if(pthread_create(&tid[0],      /*  store the ID of the created thread  */
                      0,            /*  thread attributes                   */
                      PingThread ,  /*  start routine                       */
                      (void*)(&v))) /*  arguments for start routine         */
    {
       fprintf(stderr, "error in creating thread\n");
       return 1;
    }

    if(pthread_create(&tid[1], 0, PongThread , (void*)(&v)))
    {
       fprintf(stderr, "error in creating thread\n");
       return 1;
    }


    pthread_join(tid[0], 0);
    pthread_join(tid[1], 0);

    return 0;
}
